﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

#ifndef BURNCTRLSLE_H
#define BURNCTRLSLE_H

#include <QObject>
#include <QTimer>
#include <QMap>
#include "SerialPort/UsbPort.h"
#include "BurnToolCommon/MyThread.h"
#include "BurnToolCommon/UsbPacket.h"
#include "BurnToolCommon/Global.h"

struct TlvPacket {
    uint8_t type;
    uint16_t len;
    uint8_t *data;
};

struct PayloadPacket {
    uint8_t serviceId;
    uint8_t commendId;
    uint16_t len;
    uint8_t *data;
};

enum class UpgradeTypeT {
    UPG_INFO_TYPE_VER = 0,
    UPG_INFO_TYPE_PERMIT,
    UPG_INFO_TYPE_RESEND,
    UPG_INFO_TYPE_IMAGE_FLAG,
    UPG_INFO_TYPE_ONE_EAR
};

struct TransmitStartPkt {
    uint32_t transmitId;
    uint16_t srcSend : 1;
    uint16_t pad : 15;
    uint16_t transmitType; // transmit_type
    uint32_t totalSize;
    uint32_t infoSize; // size
    uint8_t info[0];
};

struct TransmitNegotiatePkt {
    uint32_t transmitId;
    uint16_t srcSend : 1;
    uint16_t structVer : 2;
    uint16_t reTrans : 1;
    uint16_t bitmapEnable : 1;
    uint16_t pad : 11;
    uint16_t transmitType;
    uint32_t totalSize;
    uint16_t dataBlockNum;
    uint16_t dataBlockSize;
    uint32_t infoSize;
    uint8_t info[0];
};

enum class TransmitType {
    TRANSMIT_TYPE_READ_FILE, //  读文件，目的端发起
    TRANSMIT_TYPE_DUMP, // dump内容，目的端发起
    TRANSMIT_TYPE_SAVE_FILE, // 写文件，源端发起
    TRANSMIT_TYPE_SAVE_OTA_IMG
};

struct TransmitDataReplyPktF9 {
    uint32_t transmitId;
    uint32_t offset;
    uint32_t size;
    uint8_t data[0];
};

struct TransmitDataRequestItem {
    uint32_t offset;
    uint32_t size;
};

struct TransmitDataRequestPkt {
    uint32_t transmitId;
    uint32_t cnt;
    TransmitDataRequestItem item[0];
};

struct TransmitStateNotifyPkt {
    uint32_t transmitId; /* 传输ID */
    uint32_t stateCode; /* 参考 TransmitStateNotifyCode */
    uint32_t len;
    uint8_t data[0];
};

enum class TransmitStateNotifyCode {
    TRANSMIT_STATE_NOTIFY_INVALID_ID = 10,
    TRANSMIT_STATE_NOTIFY_FINISH,
    TRANSMIT_STATE_NOTIFY_FINISH_2,
    TRANSMIT_STATE_NOTIFY_DUPLICATE_ID,
    TRANSMIT_STATE_START_FRAM_RECEIVED,
    TRANSMIT_STATE_NOTIFY_FINSH_NK,
    TRANSMIT_STATE_NOTIFY_STOP,
    TRANSMIT_STATE_NOTIFY_FILE_SYSTEM_IS_AVNORMAL
};

enum class SleAckError {
    SLE_ACK_SUCCESS = 0x00,
    SLE_ACK_ERROR = 0x01,
    SLE_ACK_REQUEST_NOT_SUPPORTED = 0x02,
    SLE_ACK_NO_PERMISSION = 0x03,
    SLE_ACK_SYSTEM_BUSY = 0x04,
    SLE_ACK_REQUEST_FORMAT_ERROR = 0x05,
    SLE_ACK_PARAMETER_ERROR = 0x06,
    SLE_ACK_MEMORY_ERROR = 0x07,
    SLE_ACK_TIMEOUT = 0x08,
};

struct UpgInfoAck {
    uint16_t type;
    uint16_t size;
    uint8_t info[0];
};

namespace BurnCtrlSleClass {
class BurnCtrlSle : public QObject {
    Q_OBJECT
public:
    explicit BurnCtrlSle(QObject *parent = nullptr);
    ~BurnCtrlSle() override;
    void SetDeviceInterface(const QString &mDeviceInterface);
    bool IsBusy() const;
    void InitBurnCmdByArray(const QMap<int, BIN_INFO> &infoArray);
    bool IsOpen() const;
    void SetIsStop();
    void ReadConfig();
    void SetOneTimeBurnFlag(bool isOneTimeBurn);
    void SetDeviceInfo(SleDeviceInfo sle);
signals:
    void SignalReadThread();
    void SignalSetAddress(const QVector<SleDeviceInfo>&);
    void SignalOpenDeviceFail();
    void SignalInsertPlainText(const QString&);
    void SignalConnectResult(bool);
    void SignalSetProgress(double);
public slots:
    void SlotSendMsg(long int msgId, WPARAM wParam, LPARAM lParam);
    void SlotReadData(uint8_t *mBuffer, uint32_t bufferLen);
    void SlotOtaTimeout();
protected:
    void OpenDevice();
    void CloseDevice() const;
    void EnableSle();
    void DisableSle();
    void StartSearch();
    void StopSearch();
    void ConnectServer(WPARAM wParam, LPARAM lParam);
    void DisconnectServer(WPARAM wParam, LPARAM lParam);
    void StartBurn();
    void SendFrame(uint32_t ulPacketId, PBYTE pucPacket, uint32_t usPacketSize);
    void UpgGetInfo(uint16_t type);
    void StopBurn();
    void UpgPrepare();
    void UpgTransmitStart();
    void UpgTransmitReply(QVector<TransmitDataRequestItem> items);
    void UpgRequest();
    void PostData(int offset, int size, PBYTE mBuffer);
    int ProcessReceiveData(PayloadBuffer *&payloadBuffer);
    int ProcessReceiveDataAdd(PayloadBuffer *&payloadBuffer);
    int OtaInfoHandler(uint32_t cmdId, PBYTE pBuffer, uint32_t ulBufferSize);
    int TransmitReqHandler(PBYTE pBuffer, uint32_t ulBufferSize);
    int TransmitStateNotifyHandler(PBYTE pBuffer, uint32_t ulBufferSize);
    int ProcessACKCheck(const QVector<Tlv> &tlvVector) const;
    int DeviceScanResultsHandler(const QVector<Tlv> &tlvVector);
    void PartDeviceScanResultsHandler(SleDeviceInfo info);
    int UpgradeRequestHandler(const QVector<Tlv> &tlvVector);
    void OutputString(QString editStr);
    int UpgradeStatusHandler(PBYTE pBuffer, uint32_t ulBufferSize);
    int UpgradePrepareHandler(PBYTE pBuffer, uint32_t ulBufferSize);
    int UpgradeRequestHandler(PBYTE pBuffer, uint32_t ulBufferSize) const;
    void SetProgress(int size);
    void SaveBuffer(uint32_t cmdId, PBYTE pBuffer, uint32_t ulBufferSize);
    void StartOTATimer(int time);
    void ReadDataHandle(uint32_t &offset);
    void Close(int result) const;
private:
    QString deviceInterface;
    UsbPortClass::UsbPort *usbPort;
    MyThreadClass::MyThread *usbthread;
    QString sleAddress;
    bool isBusy;
    QMap<int, BIN_INFO> binInfoArray;
    UsbPacketClass::UsbPacket usbPacket;
    uint32_t binInfoArrayIndex;
    uint32_t mTransmitId;
    uint8_t readBuffer[MAX_BUFFER_LEN];
    uint32_t readBufferSize;
    QTimer closeTimer;
    PBYTE buffer;
    uint32_t bufferSize;
    uint32_t currentCmdId;
    QTimer *otaTimer;
    uint32_t otaTimeoutCount;
    bool isStop;
    int ms;
    int packet;
    int blockNum;
    QVector<SleDeviceInfo> vecInfo;
    SleDeviceInfo sleDeviceInfo;
    bool isOneTimeBurn = false;
    uint8_t *addr;
};
}
#endif // BURNCTRLSLE_H
